package com.cj.media.service

import android.annotation.SuppressLint
import android.app.Activity
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.PixelFormat
import android.hardware.display.DisplayManager
import android.hardware.display.VirtualDisplay
import android.media.Image
import android.media.ImageReader
import android.media.MediaRecorder
import android.media.projection.MediaProjection
import android.media.projection.MediaProjectionManager
import android.os.Binder
import android.os.IBinder
import com.cj.media.R
import com.cj.media.listener.ScreenCaptureListener
import com.cj.media.utils.NotificationUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import java.io.File
import java.nio.ByteBuffer

class ScreenShortRecordService :Service() {

    private val TAG = "ScreenShortRecordService"

    private val ioScope = CoroutineScope(Dispatchers.IO)

    private var mMediaProjectionManager: MediaProjectionManager? = null
    private var mMediaProjection: MediaProjection? = null

    //截图
    private var imageReader: ImageReader? = null

    //录屏
    private var recorder: MediaRecorder? = null
    private var virtualDisplay: VirtualDisplay? = null

    inner class ScreenShortBinder : Binder() {
        fun getService(): ScreenShortRecordService = this@ScreenShortRecordService
    }

    override fun onBind(p0: Intent?): IBinder {
        return ScreenShortBinder()
    }

    /**
     * 开始截屏
     */
    fun startCapture(intent: Intent,listener: ScreenCaptureListener){
        //开启通知，并申请成为前台服务
        NotificationUtil.startNotification(this,ScreenShortRecordService::class.java, R.drawable.ic_launcher)

        mMediaProjectionManager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
        //获取令牌
        mMediaProjection = mMediaProjectionManager?.getMediaProjection(Activity.RESULT_OK, intent)

        //配置ImageReader
        configImageReader(listener)
    }

    @SuppressLint("WrongConstant")
    private fun configImageReader(listener: ScreenCaptureListener) {
        val dm = resources.displayMetrics
        imageReader = ImageReader.newInstance(
            dm.widthPixels, dm.heightPixels,
            PixelFormat.RGBA_8888, 1
        ).apply {
            var isGot = false
            setOnImageAvailableListener({
                //这里页面帧发生变化时就会回调一次，我们只需要获取一张图片，加个标记位，避免重复
                if (!isGot) {
                    isGot = true
                    //这里就可以保存图片了
                    savePicTask(it,listener)
                }
            }, null)

            //把内容投射到ImageReader 的surface
            mMediaProjection?.createVirtualDisplay(
                TAG, dm.widthPixels, dm.heightPixels, dm.densityDpi,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, surface, null, null
            )
        }
    }

    /**
     * 保存图片
     */
    private fun savePicTask(reader: ImageReader,listener: ScreenCaptureListener) {
        ioScope.launch {
            var image: Image? = null
            try {
                //获取捕获的照片数据
                image = reader.acquireLatestImage()
                val width = image.width
                val height = image.height
                //拿到所有的 Plane 数组
                val planes = image.planes
                val plane = planes[0]

                val buffer: ByteBuffer = plane.buffer
                //相邻像素样本之间的距离，因为RGBA，所以间距是4个字节
                val pixelStride = plane.pixelStride
                //每行的宽度
                val rowStride = plane.rowStride
                //因为内存对齐问题，每个buffer 宽度不同，所以通过pixelStride * width 得到大概的宽度，
                //然后通过 rowStride 去减，得到大概的内存偏移量，不过一般都是对齐的。
                val rowPadding = rowStride - pixelStride * width
                // 创建具体的bitmap大小，由于rowPadding是RGBA 4个通道的，所以也要除以pixelStride，得到实际的宽
                val bitmap = Bitmap.createBitmap(
                    width + rowPadding / pixelStride,
                    height, Bitmap.Config.ARGB_8888
                )
                bitmap.copyPixelsFromBuffer(buffer)
                listener.onSuccess(bitmap)
                //服务退出前台
                stopForeground(true)
                mMediaProjection?.stop()
            } catch (e: java.lang.Exception) {
                e.printStackTrace()
                listener.onFailure(e)
            } finally {
                //记得关闭 image
                try {
                    image?.close()
                } catch (e: Exception) {
                }
            }
        }
    }

    //停止录制
    fun stopRecorder() {
        recorder?.stop()
        recorder?.release()
        recorder = null

        mMediaProjection?.stop()

        //退出前台服务
        stopForeground(true)
    }

    //开始录屏
    fun startRecorder(path: String, fileName: String, intent: Intent) {
        //开启通知，并申请成为前台服务
        NotificationUtil.startNotification(this,ScreenShortRecordService::class.java,R.drawable.ic_launcher)
        mMediaProjectionManager =
            getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
        //获得令牌
        mMediaProjection = mMediaProjectionManager?.getMediaProjection(Activity.RESULT_OK, intent)

        if(configMediaRecorder(path, fileName)){
            try {
                //开始录屏
                recorder?.start()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    /**
     * 配置MediaProjection
     */
    private fun configMediaRecorder(path: String, fileName: String): Boolean {

        //创建文件夹
        val dir = File(path)
        if (!dir.exists()) {
            dir.mkdirs()
        }
        val file = File(path, fileName)
        if (file.exists()) {
            file.delete()
        }
        val dm = resources.displayMetrics
        recorder = MediaRecorder()
        recorder?.apply {
            setAudioSource(MediaRecorder.AudioSource.MIC) //音频载体
            setVideoSource(MediaRecorder.VideoSource.SURFACE) //视频载体
            setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) //输出格式
            setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB) //音频格式
            setVideoEncoder(MediaRecorder.VideoEncoder.H264) //视频格式
            setVideoSize(dm.widthPixels, dm.heightPixels) //size
            setVideoFrameRate(30) //帧率
            setVideoEncodingBitRate(3 * 1024 * 1024) //比特率
            //设置文件位置
            setOutputFile(file.absolutePath)
            try {
                prepare()
                virtualDisplay = mMediaProjection?.createVirtualDisplay(
                    TAG,
                    dm.widthPixels,
                    dm.heightPixels,
                    dm.densityDpi,
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                    surface,
                    null,
                    null
                )
            } catch (e: Exception) {
                e.printStackTrace()
                return false
            }
        }
        return true
    }

    override fun onDestroy() {
        super.onDestroy()
        ioScope.cancel()
    }

    override fun onUnbind(intent: Intent?): Boolean {
        mMediaProjection?.stop()
        imageReader?.close()
        try {
            recorder?.stop()
            recorder?.release()
            recorder = null
        } catch (e: Exception) {
        }
        return super.onUnbind(intent)
    }
}